package com.googlecode.cswish.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Store key value pair
 * 
 * @author feng Date: 2009-5-27
 */
public class KeyValue implements Map<String, Object> {

	private String key;
	private String value;
	
	private Map<String, Object> exProp;
	
	public KeyValue() {
		
	}
	
	public KeyValue(String key, String value) {
		super();
		this.key = key;
		this.value = value;
	}

	public String getKey() {
		return key;
	}
	public void setKey(String key) {
		this.key = key;
	}
	public String getValue() {
		return value;
	}
	public void setValue(String value) {
		this.value = value;
	}
	
	public KeyValue clone() {
		return new KeyValue(key, value);
	}

	public Map<String, Object> getExProp() {
		return exProp;
	}

	public void setExProp(Map<String, Object> exProp) {
		this.exProp = exProp;
	}
	
	public void addExProp(String exKey, Object exValue) {
		if (exProp == null) {
			exProp = new HashMap<String, Object>();
		}
		exProp.put(exKey, exValue);
	}
	
	public Object getExProp(String exKey) {
		if (exProp == null) {
			return null;
		}
		return exProp.get(exKey);
	}

	@Override
	public int size() {
		return 2 + (exProp == null ? 0 : exProp.size());
	}

	@Override
	public boolean isEmpty() {
		return false;
	}

	@Override
	public boolean containsKey(Object key) {
		return "key".equals(key) || "value".equals(key) || exProp != null && exProp.containsKey(key);	// || "exProp".equals(key)
	}

	@Override
	public boolean containsValue(Object value) {
		return key != null && key.equals(value) || this.value != null && this.value.equals(value)
				|| exProp != null && exProp.containsValue(value);
	}

	@Override
	public Object get(Object key) {
		if ("key".equals(key)) {
			return this.key;
		} else if ("value".equals(key)) {
			return this.value;
		} else if ("exProp".equals(key)) {
			return exProp;
		} else if (exProp != null) {
			return this.exProp.get(key);
		} else {
			return null;
		}
	}

	@Override
	public Object put(String key, Object value) {
		if ("key".equals(key)) {
			String oldKey = this.key;
			this.key = value == null ? null : value.toString();
			return oldKey;
		} else if ("value".equals(key)) {
			String oldValue = this.value;
			this.value = value == null ? null : value.toString();
			return oldValue;
		} else if ("exProp".equals(key)) {
			Object oldValue = this.exProp;
			if (value instanceof Map) {
				this.exProp = (Map<String, Object>) value;
			} else if (value == null) {
				this.exProp = null;
			}
			return oldValue;
		} else {
			if (exProp == null) {
				exProp = new HashMap<String, Object>();
			}
			return exProp.put(key, value);
		}
	}

	@Override
	public Object remove(Object key) {
		if ("key".equals(key)) {
			String oldKey = this.key;
			this.key = null;
			return oldKey;
		} else if ("value".equals(key)) {
			String oldValue = this.value;
			this.value = null;
			return oldValue;
		} else if ("exProp".equals(key)) {
			Object oldValue = this.exProp;
			this.exProp = null;
			return oldValue;
		} else {
			if (exProp != null) {
				return exProp.remove(key);
			} else {
				return null;
			}
		}
	}

	@Override
	public void putAll(Map<? extends String, ? extends Object> m) {
		if (this.exProp == null) {
			this.exProp = new HashMap<String, Object>();
		}
		this.exProp.putAll(m);
		
		if (this.exProp.containsKey("key")) {
			Object key = this.exProp.remove("key");
			this.key = key == null ? null : key.toString();
		}
		if (this.exProp.containsKey("value")) {
			Object value = this.exProp.remove("value");
			this.value = value == null ? null : value.toString();
		}
	}

	@Override
	public void clear() {
		this.exProp = null;
		this.key = null;
		this.value = null;
	}

	@Override
	public Set<String> keySet() {
		int size = 2 + (this.exProp == null ? 0 : this.exProp.size());
		Set<String> set = new HashSet<String>(size * 4 / 3);
		set.add("key");
		set.add("value");
		// set.add("exProp");
		if (this.exProp != null) {
			set.addAll(this.exProp.keySet());
		}
		return set;
	}

	@Override
	public Collection<Object> values() {
		int size = 2 + (this.exProp == null ? 0 : this.exProp.size());
		List<Object> values = new ArrayList<Object>(size);
		values.add(this.key);
		values.add(this.value);
		if (this.exProp != null) {
			values.addAll(this.exProp.values());
		}
		return values;
	}

	@Override
	public Set<java.util.Map.Entry<String, Object>> entrySet() {
		int size = 2 + (this.exProp == null ? 0 : this.exProp.size());
		Map<String, Object> map = new HashMap<String, Object>(size * 4 / 3);
		map.put("key", this.key);
		map.put("value", this.value);
		//map.put("exProp", this.value);
		if (this.exProp != null) {
			map.putAll(this.exProp);
		}
		return map.entrySet();
	}
}